<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>lozyload demo</title>
  <style>
    img {
      display: block;
      margin-bottom: 50px;
      height: 200px;
      width: 400px;
    }
  </style>
</head>

<body>
  <img data-src="./src/image/1.jpg" alt="" srcset="">
  <img data-src="./src/image/2.jpg" alt="" srcset="">
  <img data-src="./src/image/3.jpg" alt="" srcset="">
  <img data-src="./src/image/4.jpg" alt="" srcset="">
  <img data-src="./src/image/5.jpg" alt="" srcset="">
  <img data-src="./src/image/6.jpg" alt="" srcset="">
  <img data-src="./src/image/7.jpg" alt="" srcset="">
  <img data-src="./src/image/8.jpg" alt="" srcset="">
  <img data-src="./src/image/9.jpg" alt="" srcset="">
  <img data-src="./src/image/10.jpg" alt="" srcset="">

  <script>
    function lazyload() {
      let viewHeight = document.body.clientHeight //获取可视区高度
      let imgs = document.querySelectorAll('img[data-src]')
      imgs.forEach((item, index) => {
        if (item.dataset.src === '') return

        // 用于获得页面中某个元素的左，上，右和下分别相对浏览器视窗的位置
        let rect = item.getBoundingClientRect()
        if (rect.bottom >= 0 && rect.top < viewHeight) {
          item.src = item.dataset.src
          item.removeAttribute("data-src")
        }
      })
    }

    // 简单节流
    function throttle(fn, delay) {
      let flag = false;

      return function () {
        if (flag) return;

        flag = true;
        setTimeout(() => {
          fn.call(this, arguments);
          flag = false;
        }, delay);
      };
    }

    // const imgs = document.querySelectorAll('img[data-src]')
    // const config = {
    //   rootMargin: '0px',
    //   threshold: 0,
    // }
    // let observer = new IntersectionObserver((entries, self) => {
    //   entries.forEach((entry) => {
    //     if (entry.isIntersecting) {
    //       let img = entry.target
    //       let src = img.dataset.src
    //       if (src) {
    //         img.src = src
    //         img.removeAttribute('data-src')
    //       }
    //       // 解除观察
    //       self.unobserve(entry.target)
    //     }
    //   })
    // }, config)

    // imgs.forEach((image) => {
    //   observer.observe(image)
    // })

    class InterObser {
      constructor(attr = 'data-src', defaultImg, opts = {}) {
        this.attr = attr;
        this.defaultImg = defaultImg;
        this.opts = opts;

        this.install();
        this.update();
      }

      install() {
        // IntersectionObserver就是观察一个元素是否在当前窗口中 该API是异步的
        // io.observe(document.querySelector('img')); // 开始观察，接受一个DOM节点对象
        // io.unobserve(element); // 停止观察 接受一个element元素
        // io.disconnect(); // 关闭观察器


        // time：可见性发生变化的时间，是一个高精度时间戳，单位为毫秒
        // target：被观察的目标元素，是一个 DOM 节点对象
        // isIntersecting: 目标是否可见
        // rootBounds：根元素的矩形区域的信息，getBoundingClientRect()方法的返回值，如果没有根元素（即直接相对于视口滚动），则返回 null
        // boundingClientRect：目标元素的矩形区域的信息
        // intersectionRect：目标元素与视口（或根元素）的交叉区域的信息
        // intersectionRatio：目标元素的可见比例，即 intersectionRect 占 boundingClientRect 的比例，完全可见时为 1，完全不可见时小于等于 0


        // 初始化 IntersectionObserver 实例  
        this.io = new IntersectionObserver(entrys => {
          // 监听到元素进去窗口时，循环每个监听器
          entrys.forEach(ele => {
            // 如果该监听器进入窗口，则真实得替换占位图
            if (ele.isIntersecting) {
              this.loadImg(ele);
              // 停止怼该监听器得监听，防止多次操作
              this.io.unobserve(ele.target);
            }
          })
        }, this.opts)
      }

      // 加载图片 将data-src赋值给src
      loadImg(ele) {
        const url = ele.target.dataset.src;
        ele.target.src = url;
      }

      update() {
        const els = document.querySelectorAll(`[${this.attr}]`);
        // 为每个监听器设置默认值
        els.forEach(el => {
          el.src = this.defaultImg;
          // 开始监听
          this.io.observe(el);
        })
      }
    }

    if (IntersectionObserver) {
      // 调用
      new InterObser('data-src', './src/image/default.jpg', { threshold: [1] })
    } else {
      lazyload() // 刚开始还没滚动屏幕时，要先触发一次函数，初始化首页的页面图片
      window.addEventListener("scroll", throttle(lazyload, 200))
    }

  </script>
</body>

</html>